package com.abf.okhttp.web;

import com.abf.okhttp.entity.MyUser2;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: LCG
 * 作者: LCG
 * 日期: 2021/3/24  8:16
 * 描述:
 */

@RestController
public class TestMyHttpClientController {


    /**
     * 作者: LCG
     * 日期: 2021/3/24  8:17
     * 描述: 测试OKHttpClient 发送Get请求
     * @Param []
     * @Return void
     */
    @RequestMapping("testGet")
    public void testGetRequest() throws IOException {

        //1构建OKHttpClient客户端
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                //发请求给对方传递数据的超时时间
                .writeTimeout(100, TimeUnit.SECONDS)
                //接收请求返回的数据的超时时间(适合于对方服务器处理业务时间比较长的场景)
                .readTimeout(5, TimeUnit.SECONDS)
                //链接的超时时间
                .connectTimeout(100, TimeUnit.SECONDS)
                //等待创建请求的超时时间
                .callTimeout(100, TimeUnit.SECONDS)
                //注意这个connectionPool的使用 默认会创建5个链接并维持 5分钟，那么在上传的环境中就可能有一些问题
                //比如上传成功后对方服务器关闭TCP链接但是，自己本地连接池里边的链接还在，那么在复用的时候会出现，连接超时的
                //情况，这时候如果是这种情况应该设置默认的连接池不缓存空闲链接，这样每次请求都创建新的链接会避免该问题
                //因此可以设置一下的配置来实现配置连接池不缓存链接
                //.connectionPool(new ConnectionPool(0,1,TimeUnit.SECONDS))
                .build();

        //使用默认的参数创建客户端
        /*OkHttpClient okHttpClient=new OkHttpClient();*/

        //2 构建请求
        Request request = new Request.Builder()
                //你要访问的对方的服务器的地址
                .url("http://localhost:10001/testGet?userName=张三&password=123456")
                //请求方式 GET
                .get()
                //添加请求头信息
                .addHeader("token", "11233456789")
                .build();

        //3、发送请求
        Response execute =null;
        ResponseBody body=null;
        try{
           //3、发送请求
           execute = okHttpClient.newCall(request).execute();

           //4、处理响应  获取响应体内容
           body = execute.body();
           //5、读取响应体中的内容
            //byte[] bytes = body.bytes();
            String string = body.string();
            //怎么去解析数据
            //JSONObject jsonObject = JSON.parseObject(string);
            Map<String,Object> map = JSON.parseObject(string, Map.class);
            //String json = new String(bytes);
            if(map.get("status")==null){
                System.out.println("---成功--获取的响应结果----->"+map.get("returnData"));
            }else{
                //当客户端调用服务端的时候 被调用的服务端出现异常（比如 服务端抛出 RuntimeException）
                System.out.println(string);
                System.out.println("---成功--获取的响应结果--异常信息--->"+map.get("message"));
            }

       }catch (Exception e){
            //当客户端调用服务端的时候客户端出错（比如 各种超时和网络异常 会被 catch）
            e.printStackTrace();

            //if(body!=null){
                byte[] bytes = body.bytes();
                String jsonError = new String(bytes);
                System.out.println("============"+jsonError);
           // }


       }

    }


    /**
     * 作者: LCG
     * 日期: 2021/3/24  9:07
     * 描述: 测试 POST请求 提交JSON数据
     * @Param []
     * @Return void
     */
    @RequestMapping("testPost1")
    public void  testPostJson() throws IOException {

        //1构建OKHttpClient客户端
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                //发请求给对方传递数据的超时时间
                .writeTimeout(100, TimeUnit.SECONDS)
                //接收请求返回的数据的超时时间(适合于对方服务器处理业务时间比较长的场景)
                .readTimeout(5, TimeUnit.SECONDS)
                //链接的超时时间
                .connectTimeout(100, TimeUnit.SECONDS)
                //等待创建请求的超时时间
                .callTimeout(100, TimeUnit.SECONDS)
                .build();

        //2、构建JSON数据 使用RequestBody
        Map<String,Object> map=new HashMap<>();
        map.put("userName","张三");
        map.put("password","123sdhsdjksfd#%$@");
        RequestBody requestBody = FormBody.create(MediaType.parse("application/json"), JSON.toJSONString(map));

        //3、构建请求
        Request request = new Request.Builder()
                .addHeader("token", "1234569877")
                .post(requestBody)
                .url("http://localhost:10001/testPost1")
                .build();

        //4、发送请求 获取响应内容  记得自己 try catch 一下 我这里不写了 大家 仿照上文的  get请求去处理
        ResponseBody body = okHttpClient.newCall(request).execute().body();

        //处理响应结果
        System.out.println( body.string());
    }


    /**
     * 作者: LCG
     * 日期: 2021/3/24  9:23
     * 描述: post请求提交form表单
     * @Param []
     * @Return void
     */
    @RequestMapping("testPost2")
    public void  testPostFormData(@org.springframework.web.bind.annotation.RequestBody Map<String,Object> mmp) throws IOException {

        //1构建OKHttpClient客户端
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                //发请求给对方传递数据的超时时间
                .writeTimeout(100, TimeUnit.SECONDS)
                //接收请求返回的数据的超时时间(适合于对方服务器处理业务时间比较长的场景)
                .readTimeout(5, TimeUnit.SECONDS)
                //链接的超时时间
                .connectTimeout(100, TimeUnit.SECONDS)
                //等待创建请求的超时时间
                .callTimeout(100, TimeUnit.SECONDS)
                .build();

        //2构建form 表单 参数很多大家可以通过For循环去添加
        FormBody.Builder builder = new FormBody.Builder();
        for (Map.Entry<String, Object> stringObjectEntry : mmp.entrySet()) {
            builder.add(stringObjectEntry.getKey(),stringObjectEntry.getValue().toString());
        }
        FormBody build = builder.build();

        //3、构建请求
        Request request = new Request.Builder()
                .addHeader("token", "1234569877")
                .post(build)
                .url("http://localhost:10001/testPost2")
                .build();

        //4、发送请求 获取响应内容  记得自己 try catch 一下 我这里不写了 大家 仿照上文的  get请求去处理
        ResponseBody body = okHttpClient.newCall(request).execute().body();

        //处理响应结果
        System.out.println( body.string());

    }



    /**
     * 作者: LCG
     * 日期: 2021/3/24  9:42
     * 描述: 基于Form表单 Base64传递文件
     * @Param []
     * @Return void
     */
    @RequestMapping("testPost3")
    public void testPOST3(MultipartFile[] files, MyUser2 myUser2) throws IOException {

        //1构建OKHttpClient客户端
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                //发请求给对方传递数据的超时时间
                .writeTimeout(100, TimeUnit.SECONDS)
                //接收请求返回的数据的超时时间(适合于对方服务器处理业务时间比较长的场景)
                .readTimeout(100, TimeUnit.SECONDS)
                //链接的超时时间
                .connectTimeout(100, TimeUnit.SECONDS)
                //等待创建请求的超时时间
                .callTimeout(100, TimeUnit.SECONDS)
                .build();

        //构建form表单
        String filename1 = files[0].getOriginalFilename();

        BASE64Encoder base64Encoder=new BASE64Encoder();
        String encode1 = base64Encoder.encode(files[0].getBytes());

        FormBody.Builder builder = new FormBody.Builder();



        builder.add("userName",myUser2.getUserName())
                .add("password",myUser2.getPassword())
                .add("image",encode1)
                .add("filename",filename1);


        FormBody formBody = builder.build();


        //3、构建请求
        Request request = new Request.Builder()
                .addHeader("token", "1234569877")
                .post(formBody)
                .url("http://localhost:10001/testPost3")
                .build();

        //4、发送请求 获取响应内容  记得自己 try catch 一下 我这里不写了 大家 仿照上文的  get请求去处理
        ResponseBody body = okHttpClient.newCall(request).execute().body();

        //处理响应结果
        System.out.println( body.string());

    }

    

    /**
     * 作者: LCG
     * 日期: 2021/3/24  13:05
     * 描述: 使用multipart/form-data 上传文件和数据
     * @Param [files, myUser2]
     * @Return void
     */
    @RequestMapping("testPost4")
    public Object testPost4(MultipartFile[] files,MyUser2 myUser2) throws IOException {

        //构建一个MultipartBody
        MultipartBody.Builder builder = new MultipartBody.Builder()
                .addFormDataPart("userName", myUser2.getUserName())
                .addFormDataPart("password", myUser2.getPassword());

        //构建文件类型的请求体
        for (MultipartFile file : files) {
            RequestBody requestBody = MultipartBody.create(MediaType.parse("multipart/form-data"), files[0].getBytes());
            builder.addFormDataPart("files",file.getOriginalFilename(),requestBody);
        }

        MultipartBody multipartBody = builder.build();

        //构建请求客户端
        //1构建OKHttpClient客户端
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                //发请求给对方传递数据的超时时间
                .writeTimeout(100, TimeUnit.SECONDS)
                //接收请求返回的数据的超时时间(适合于对方服务器处理业务时间比较长的场景)
                .readTimeout(10, TimeUnit.SECONDS)
                //链接的超时时间
                .connectTimeout(10, TimeUnit.SECONDS)
                //等待创建请求的超时时间
                .callTimeout(100, TimeUnit.SECONDS)
                .build();

        //2、构建请求
        Request request = new Request.Builder()
                .addHeader("token", "1234569877")
                .post(multipartBody)
                .url("http://localhost:10001/testPost4")
                .build();
        Call call = null;
        Response response=null;
        try{
            call=okHttpClient.newCall(request);
           //发送请求并执行
            response = call.execute();
           //解析返回的数据
            String string = response.body().string();
            JSONObject jsonObject = JSON.parseObject(string);

            if(jsonObject.get("status")==null){
                System.out.println("+++++SUCCESS++++++>"+jsonObject.toJSONString());
                return jsonObject;
            }else{
                //说明服务端出错了
                System.out.println("==========调用的服务坏了===========");
                return "==========server error===========";
            }


        }catch (Exception e){
            e.printStackTrace();
         //说明是客户端出错了  readTime  connectionTimeOut  writeTimeOut callTimeout
         //如果是这种情况按照公司的业务去处理即可

            return "客户端调用超时=》"+e.getMessage();
       }

    }

}
